home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / keyb / rbkeyswp.zip / RBKEYSWP.ASM < prev    next >
Assembly Source File  |  1991-06-22  |  9KB  |  233 lines

  1. ;**************************************************************************
  2. ;*                                      *
  3. ;*   RBkeyswap     v2.0       6/22/91                      *
  4. ;*   (c) Copyright 1989, 1991 Ralf Brown                  *
  5. ;*                                      *
  6. ;*   Permission is granted to redistribute unmodified copies in their      *
  7. ;*   entirety.    Modified copies may be distributed provided that they      *
  8. ;*   are clearly marked as modified and the original unmodified source      *
  9. ;*   code is distributed together with the modification.          *
  10. ;*                                      *
  11. ;*   ------------------------------------------------------------------   *
  12. ;*                                      *
  13. ;*   RBkeyswap is a program to fix the IBM's enhanced keyboard, which     *
  14. ;*   places the Escape, Control, and CapsLock keys in the wrong places.   *
  15. ;*   After running RBkeyswap, Escape and `/~ will be exchanged, as will   *
  16. ;*   the left control key and the CapsLock key.  The right control key      *
  17. ;*   will be unaffected.                          *
  18. ;*                                      *
  19. ;*   RBkeyswap loads itself high (no need for LOADHI or LH) into either   *
  20. ;*   an XMS upper memory block or a DOS 5.0 UMB.  If neither is avail-      *
  21. ;*   able, RBkeyswap will go resident in low memory, using just 128      *
  22. ;*   bytes (it needs a mere 64 bytes in high memory).  Note that it will  *
  23. ;*   use 272 bytes under DOS 2.x, because those versions force all TSRs   *
  24. ;*   to leave at least that much resident.                  *
  25. ;*                                      *
  26. ;*   You need a BIOS which provides the keyboard intercept on INT 15h.      *
  27. ;*   If your BIOS does not support this, RBkeyswap will merely use up      *
  28. ;*   memory without doing anything.                      *
  29. ;*                                      *
  30. ;*   Usage:   RBKEYSWP                              *
  31. ;*   Note: the program does not check whether it is already installed,      *
  32. ;*     so a second run will re-swap the keys, negating the action and      *
  33. ;*     using up a small amount of extra memory.               *
  34. ;*                                      *
  35. ;*   ------------------------------------------------------------------   *
  36. ;*                                      *
  37. ;*   Rebuilding RBkeyswap:                          *
  38. ;*      TASM RBKEYSWP                           *
  39. ;*      TLINK /T RBKEYSWP                          *
  40. ;*                                      *
  41. ;**************************************************************************
  42.  
  43. code segment 'code'
  44.        assume    cs:code
  45.  
  46.        org    2Ch
  47. envseg dw    ?            ; segment address of our environment
  48.  
  49.        org    100h
  50. RBkeyswap:
  51.        jmp    init
  52.  
  53. banner db    13,"RBkeyswap 2.0",9,"(c) Copyright 1989, 1991 Ralf Brown",13,10
  54.        db    "Swaps Esc/tilde and CapsLock/LeftCtrl",13,10,"$"
  55.        db    26     ; stop output here if TYPEing the .COM file
  56.  
  57. ;--------------------------------------------------------------------------
  58.  
  59. int15_handler:
  60.        jnc    not_ours ; has a previous handler said to ignore scan code?
  61.        cmp    ah,4Fh            ; scan code translation?
  62.        jne    not_ours        ; if not, chain immediately
  63.        cmp    al,0E1h         ; is it a special key such as "Pause"?
  64.        je    int15_setbranch
  65.        cmp    al,0E0h         ; or a right-{alt,ctrl}?
  66. _branch:                ; (if prev scan was E0h or E1h, we will
  67. BRANCH equ (_branch-int15_handler)    ;   branch unconditionally)
  68.        je    int15_setbranch     ; the opcode here gets toggled between
  69.                     ;   JE and JMP SHORT as needed
  70.        shl    al,1            ; move break bit into CF
  71.        pushf                ;   and remember it for later
  72.        cmp    al,1Dh*2        ; ctrl?
  73.        je    ctrl_or_capslock
  74.        cmp    al,3Ah*2        ; capslock?
  75.        je    ctrl_or_capslock
  76.        cmp    al,01h*2        ; ESC?
  77.        je    esc_or_tilde
  78.        cmp    al,29h*2        ; backquote/tilde key?
  79.        jne    int15_no_xlat
  80. esc_or_tilde:
  81.        xor    al,0Fh*2        ; (AL xor 0F) xor 27 == (AL xor 28h)
  82.                     ; 01h -> 29h, 29h -> 01h
  83.                     ; thus esc and tilde swapped
  84. ctrl_or_capslock:
  85.        xor    al,27h*2        ; 1Dh -> 3Ah, 3Ah -> 1Dh
  86.                     ; thus left-ctrl and capslock swapped
  87. int15_no_xlat:
  88.        popf                ; retrieve break bit in CF
  89.        rcr    al,1            ;   and add to translated scan code
  90.        jmp short int15_done
  91.  
  92. int15_setbranch:
  93.        xor    byte ptr cs:BRANCH,(74h xor 0EBh) ; toggle between JE and JMP
  94. int15_done:
  95.        stc                ; use the scan code
  96. not_ours:
  97.        db    0EAh            ; FAR JMP chain to previous handler
  98. old_int15 dd    ?
  99.  
  100. end_resident label byte
  101. code_size equ $ - int15_handler
  102. resident_code equ (code_size + 15)/16
  103.  
  104. ;--------------------------------------------------------------------------
  105.  
  106. xms_entry     dd 0
  107. resident_seg  dw 0     ; location of interrupt handler after relocation
  108. resident_size dw 0     ; number of paras to keep on going TSR
  109. alloc_strat   dw 0
  110. link_state    db 0     ; are UMBs part of memory chain?
  111. exit_func     db 4Ch   ; will change to 31h if we must go resident
  112.  
  113.        assume    ds:code
  114. init:
  115.     mov    dx,offset banner
  116.     mov    ah,9
  117.     int    21h            ; identify ourself
  118.     mov    ax,3515h
  119.     int    21h            ; get old vector
  120.     mov    word ptr old_int15,bx    ; and store in new interrupt handler
  121.     mov    word ptr old_int15 + 2,es
  122.  ; first, see if we can load into an XMS upper memory block
  123.     mov    ax,352Fh
  124.     int    21h            ; find out whether INT 2F is valid
  125.     mov    ax,es
  126.     or    ax,bx            ; don't try XMS if INT 2F is NULL
  127.     jz    no_XMS            ; (could be case under DOS 2.x)
  128.     mov    ax,4300h        ; see if XMS is installed
  129.     int    2Fh
  130.     cmp    al,80h            ; did XMS respond?
  131.     jnz    no_XMS
  132.     mov    ax,4310h        ; if XMS present, get its entry point
  133.     int    2Fh
  134.     mov    word ptr xms_entry,bx
  135.     mov    word ptr xms_entry+2,es ; and store entry point for call
  136.     mov    ah,10h            ; request UMB
  137.     mov    dx,resident_code    ; this is how much we need
  138.     call    xms_entry        ; ask XMS for the memory
  139.     cmp    ax,1            ; did we get it?
  140.     jne    no_XMS            ; if not, try DOS 5 UMB
  141.     mov    resident_seg,bx     ; remember where we'll relocate
  142.     jmp    relocate_handler    ; and go install
  143.  ; if no XMS, try a DOS5 UMB
  144. no_XMS:
  145.     mov    ax,3000h        ; get DOS version
  146.     int    21h
  147.     cmp    al,5            ; DOS 5.0 or higher?
  148.     jb    not_dos5
  149.     cmp    al,10            ; but make sure not OS/2 penalty box
  150.     jae    not_dos5
  151.     mov    ax,5802h        ; get UMB link state
  152.     int    21h
  153.     mov    link_state,al        ; and remember it for later restore
  154.     mov    ax,5803h        ; set link state
  155.     mov    bx,1            ;   UMBs are part of memory chain
  156.     int    21h
  157.     mov    ax,5800h        ; get allocation strategy
  158.     int    21h
  159.     mov    alloc_strat,ax        ; and remember it for later restore
  160.     mov    ax,5801h        ; set allocation strategy
  161.     mov    bx,40h            ;   alloc high memory only
  162.     int    21h
  163.     mov    ah,48h            ; allocate memory
  164.     mov    bx,resident_code    ;   this is how much we need
  165.     int    21h            ; try to allocate the UMB
  166.     pushf                ; remember whether we succeeded
  167.     jc    no_highmem        ; did we succeed?
  168.     mov    resident_seg,ax     ; yes, so remember where to relocate
  169.     dec    ax            ; address the MCB for our new memory
  170.     mov    es,ax            ;   block
  171.     mov    word ptr es:[1],0Ah    ; make DOS owner of UMB, so it won't be
  172.     mov    word ptr es:[8],"CS"    ; released when we exit (details below)
  173. ;---------------------------
  174. ; Reasons for mucking with the MCB:
  175. ;    DOS 5 will release any memory blocks owned by the program when
  176. ;    it exits without going TSR, even if the blocks are in high memory
  177. ;    and high memory has been disconnected from the memory chain.  So,
  178. ;    we need to change the owner field such that DOS thinks it belongs to
  179. ;    somebody else and doesn't release it when we exit.  Both 08h and
  180. ;    0Ah are used by DOS itself, so we know they won't be messed with.
  181. ;    However, the DOS 5 MEM program gets confused by 08h, because it
  182. ;    thinks the block should have subblocks, which it doesn't.  0Ah is
  183. ;    normally a locked-out portion of high memory, so there aren't any
  184. ;    problems there.  I put "SC" in the name field to make DOS think
  185. ;    this is "system code".
  186. ;---------------------------
  187. no_highmem:
  188.     mov    ax,5801h
  189.     mov    bx,alloc_strat        ; restore allocation strategy
  190.     int    21h
  191.     mov    ax,5803h        ; restore link state
  192.     mov    bh,0
  193.     mov    bl,link_state
  194.     int    21h
  195.     popf                ; get back whether we were successful
  196.     jnc    relocate_handler    ; if successful, go install
  197.  ; as a last resort, use our own PSP to store the code, and go resident
  198. not_dos5:
  199.     mov    ax,cs
  200.     add    ax,4            ; copy to offset 40h in PSP
  201.     mov    resident_seg,ax
  202.     mov    exit_func,31h        ; TSR rather than normal exit
  203.     mov    ah,49h            ; since we will be going resident,
  204.     mov    es,envseg        ;   discard our environment
  205.     int    21h
  206.     mov    envseg,0        ;   and zero the ptr in the PSP
  207.     mov    resident_size,resident_code + 4
  208. relocate_handler:
  209.  ; relocate interrup